package com.guigu.guliware.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.guigu.gulicommon.constant.enumes.order.OrderStatus;
import com.guigu.gulicommon.entity.dto.WareSkuLockDto;
import com.guigu.gulicommon.entity.dto.mq.StockLockedDto;
import com.guigu.gulicommon.entity.pojo.SkuWareHasStockPoJo;
import com.guigu.gulicommon.entity.pojo.StockDetailPoJo;
import com.guigu.gulicommon.entity.pojo.res.Res;
import com.guigu.gulicommon.entity.vo.HasStockSkuVo;
import com.guigu.gulicommon.entity.vo.LockStockVo;
import com.guigu.gulicommon.entity.vo.OmsOrderVo;
import com.guigu.gulicommon.exception.BaseException;
import com.guigu.guliware.entity.WmsWareOrderTask;
import com.guigu.guliware.entity.WmsWareOrderTaskDetail;
import com.guigu.guliware.entity.WmsWareSku;
import com.guigu.guliware.exception.NoHasStockException;
import com.guigu.guliware.feign.OrderServer;
import com.guigu.guliware.mapper.WmsWareOrderTaskDetailMapper;
import com.guigu.guliware.mapper.WmsWareOrderTaskMapper;
import com.guigu.guliware.mapper.WmsWareSkuMapper;
import com.guigu.guliware.service.IWmsWareSkuService;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

import static com.guigu.gulicommon.constant.MQConstant.*;
import static com.guigu.gulicommon.constant.enumes.res.OtherResCode.LOCK_STOCK_SUCCESS;
import static com.guigu.gulicommon.constant.enumes.res.OtherResCode.PRODUCT_NO_HAS_STOCK_ERROR;
import static com.guigu.gulicommon.constant.enumes.res.SelectResCode.*;
import static com.guigu.gulicommon.constant.enumes.ware.HasStock.NO;
import static com.guigu.gulicommon.constant.enumes.ware.HasStock.YES;
import static com.guigu.gulicommon.constant.enumes.ware.LockStatus.LOCKED;

/**
 * <p>
 * 商品库存 服务实现类
 * </p>
 *
 * @author 陈俊杰
 * @since 2024-08-24
 */
@RabbitListener(queues = STOCK_RELEASE_QUEUE)
@Service
public class WmsWareSkuServiceImpl extends ServiceImpl<WmsWareSkuMapper, WmsWareSku> implements IWmsWareSkuService {
    @Autowired
    private OrderServer orderServer;

    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private WmsWareOrderTaskMapper wmsWareOrderTaskMapper;
    @Autowired
    private WmsWareOrderTaskDetailMapper wmsWareOrderTaskDetailMapper;

    /**
     * 根据skuId查询商品库存
     *
     * @param skuIds skuId
     * @return 单款商品库存信息
     */
    @Override
    public Res<HasStockSkuVo> getStockBySkuIds(List<Long> skuIds) {
        //1 查询库存
        List<WmsWareSku> wareSkus = new LambdaQueryChainWrapper<>(this.baseMapper)
                .in(WmsWareSku::getSkuId, skuIds)
                .list();
        //2 判断库存是否存在, 不存在抛出异常
        if (wareSkus.isEmpty()) {
            throw new BaseException(SELECT_SKU_FILE_NOT_EXIST);
        }
        //3 计算库存
        List<HasStockSkuVo> wareSkuVos = wareSkus.stream().map(wareSku -> {
            HasStockSkuVo wmsWareSkuVo = new HasStockSkuVo();
            BeanUtil.copyProperties(wareSku, wmsWareSkuVo);
            //库存大于0为有否则为无
            wmsWareSkuVo.setHasStock((wareSku.getStock() - wareSku.getStockLocked()) > 0 ? YES : NO);
            return wmsWareSkuVo;
        }).collect(Collectors.toList());
        return new Res<>(SELECT_SKU_STOCK_SUCCESS, wareSkuVos);
    }

    /**
     * 锁定订单对应的商品库存
     *
     * @param wareSkuLockDto 锁定库存信息
     * @return 锁定结果
     */
    @Override
    @Transactional
    public Res<LockStockVo> orderLockStock(WareSkuLockDto wareSkuLockDto) {
        //保存库存工作单详情,方便追溯

        WmsWareOrderTask orderTask = new WmsWareOrderTask()
                .setOrderSn(wareSkuLockDto.getOrderSn());
        wmsWareOrderTaskMapper.insert(orderTask);


        //遍历出要锁定的商品的Id
        List<SkuWareHasStockPoJo> collect = wareSkuLockDto.getLocks().stream().map(
                i -> {
                    SkuWareHasStockPoJo skuWareHasStockPoJo = new SkuWareHasStockPoJo();
                    skuWareHasStockPoJo.setSkuId(i.getSkuId());
                    List<Long> wareIds = this.baseMapper.selectListWareIdHasStock(i.getSkuId());
                    skuWareHasStockPoJo.setWareIds(wareIds).setNum(i.getCount());
                    return skuWareHasStockPoJo;
                }
        ).collect(Collectors.toList());
        //锁定库存
        for (SkuWareHasStockPoJo skuWareHasStockPoJo : collect) {
            //判断是否还有库存
            boolean lock = false;
            Long skuId = skuWareHasStockPoJo.getSkuId();
            List<Long> wareIds = skuWareHasStockPoJo.getWareIds();
            //如果没有库存, 抛出异常
            if (wareIds == null || wareIds.isEmpty()) {
                throw new NoHasStockException(skuId, PRODUCT_NO_HAS_STOCK_ERROR);
            }
            for (Long wareId : wareIds) {
                //锁定库存
                Long count = this.baseMapper.lockSkuStock(skuId, wareId, skuWareHasStockPoJo.getNum());
                //判断是否锁定成功
                if (count >= 1) {
                    lock = true;
                    //通过MQ告诉订单服务库存锁定成功
                    WmsWareOrderTaskDetail wareOrderTaskDetail = new WmsWareOrderTaskDetail()
                            .setSkuId(skuId)
                            .setWareId(wareId)
                            .setSkuNum(Math.toIntExact(skuWareHasStockPoJo.getNum()))
                            .setLockStatus(LOCKED)
                            .setTaskId(orderTask.getId());

                    StockDetailPoJo stockDetailPoJo = new StockDetailPoJo();
                    BeanUtil.copyProperties(wareOrderTaskDetail, stockDetailPoJo);

                    wmsWareOrderTaskDetailMapper.insert(wareOrderTaskDetail);
                    StockLockedDto stockLockedDto = new StockLockedDto()
                            .setId(orderTask.getId())
                            .setStockDetailPoJo(stockDetailPoJo);
                    rabbitTemplate.convertAndSend(STOCK_EVENT_EXCHANGE, STOCK_LOCKED_ROUTING_KEY, stockLockedDto);
                    break;
                } else {
                    //当前仓库锁定失败, 重新尝试其他仓库
                }
            }
            if (!lock) {
                throw new NoHasStockException(skuId, PRODUCT_NO_HAS_STOCK_ERROR);
            }
        }
        return new Res<>(LOCK_STOCK_SUCCESS);
    }

    /**
     * 监听库存解锁,锁定队列
     *
     * @param dto     解锁库存信息
     * @param message 消息
     */
    @Override
    @RabbitHandler
    public void handleStockLockedRelease(StockLockedDto dto, Message message) {
        Long id = dto.getId();
        StockDetailPoJo detail = dto.getStockDetailPoJo();
        Long skuId = detail.getSkuId();
        Long detailId = detail.getId();
        Long wareId = detail.getWareId();
        //1. 查询数据库关于这个订单的锁定库存信息
        WmsWareOrderTaskDetail wareOrderTaskDetail = wmsWareOrderTaskDetailMapper.selectById(detailId);
        if (wareOrderTaskDetail != null) {
            //解锁
            //1.1 查询订单状态
            WmsWareOrderTask orderTask = wmsWareOrderTaskMapper.selectById(id);
            String orderSn = orderTask.getOrderSn();
            Res<OmsOrderVo> omsOrderVoRes = orderServer.getOrderStatusBySn(orderSn);
            if (!omsOrderVoRes.getCode().equals(SELECT_ORDER_DETAIL_SUCCESS.getCode())) {
                throw new BaseException(omsOrderVoRes.getCode(), omsOrderVoRes.getMsg());
            } else {
                if (omsOrderVoRes.getData().get(0).getStatus().equals(OrderStatus.CANCELLED)) {
                    //订单已经被取消了或不存在了, 解锁库存
                    this.unlockStock(skuId, wareId, Long.valueOf(detail.getSkuNum()), detailId);
                }
            }
        } else {
            //没有这个订单, 不用解锁
            return;
        }
    }

    /**
     * 解锁库存
     *
     * @param skuId        商品skuId
     * @param wareId       仓库id
     * @param num          解锁库存的数量
     * @param taskDetailId 锁定库存的详情id
     */
    private void unlockStock(Long skuId, Long wareId, Long num, Long taskDetailId) {
        this.baseMapper.unlockStock(skuId, wareId, num);
        //  wmsWareOrderTaskDetailMapper.updateById(taskDetail);
    }
}
